using System;
using System.Collections.Generic;

using Microsoft.Practices.CompositeWeb;

using MVPComposibility.ContactManager.DomainModel;
using MVPComposibility.ContactManager.Services;
using MVPComposibility.ContactManager.Views.ContactList;
using WCSFContrib.Extensions.Utility;

namespace MVPComposibility.ContactManager.Views.ContactList
{
	public class ContactListModel : IContactListModel
	{
		private int _selectedContactIndex = -1;
		private ContactService _contactService;
		
		[ServiceDependency]
		public ContactService ContactService
		{
			set { _contactService = value; }
		}

		#region IContactListModel Implementation

		public event EventHandler SelectedContactChanged;
		public event EventHandler<DataEventArgs<Contact>> SelectedContactChangedGeneric;
		public event EventHandler<DataEventArgs<Contact>> InitializedGeneric;
		public event EventHandler ContentChanged;
		public event EventHandler Initialized;

		public Contact SelectedContact
		{
			get { return _selectedContactIndex == -1 ? null : _contactService.GetContact(_selectedContactIndex); }
		}

		public int SelectedContactIndex
		{
			get { return _selectedContactIndex; }
			set
			{
				if(_selectedContactIndex != value)
				{
					UpdateSelectedContactIndex(value);
					OnSelectedContactChanged(this, EventArgs.Empty);
					OnSelectedContactChangedGeneric(_selectedContactIndex);
				}
			}
		}

		public virtual IEnumerable<Contact> GetAllContacts()
		{
			return _contactService.GetAllContacts();
		}


		/// <summary>
		/// Called when the model is reloaded after a postback. This restores
		/// the currently selected model index, but does not fire the
		/// SelectedContactChanged event.
		/// </summary>
		/// <param name="selectedContactIndex">The index of the currently selected contact.</param>
		public virtual void RestoreSelectedContactFromPersistentState(int selectedContactIndex)
		{
			UpdateSelectedContactIndex(selectedContactIndex);
			OnInitialized(this, EventArgs.Empty);
			OnInitializedGeneric(selectedContactIndex);
		}

		public void ContentChange()
		{
			OnContentChanged(this, EventArgs.Empty);
		}

		public void ContactNameChanged()
		{
			// Note: I really could do something with the event args here but in this silly sample I just reload the whole content.
			// One way of using this event information would be to send the NewContactName to the presenter by means
			// of an event and then pass it into the view which would then raise it's Changed event to the page handler
			// which would call UpdatePanel.Update().
			ContentChange();
		}

		#endregion

		#region Event raising helpers

		protected virtual void OnSelectedContactChanged(object sender, EventArgs e)
		{
			if(SelectedContactChanged != null)
			{
				SelectedContactChanged(sender, e);
			}
		}

		protected virtual void OnSelectedContactChangedGeneric(int selectedContactIndex)
		{
			if (selectedContactIndex >= 0 && SelectedContactChangedGeneric != null)
			{
				List<Contact> list = new List<Contact>(GetAllContacts());
				Contact data = list[selectedContactIndex];
				SelectedContactChangedGeneric(this, new DataEventArgs<Contact>(data));
			}
		}

		protected virtual void OnInitializedGeneric(int selectedContactIndex)
		{
			Contact data = null;
			if (selectedContactIndex >= 0)
			{
				List<Contact> list = new List<Contact>(GetAllContacts());
				data = list[selectedContactIndex];
			}
			if (InitializedGeneric != null)
			{
				InitializedGeneric(this, new DataEventArgs<Contact>(data));
			}
		}

		protected virtual void OnContentChanged(object sender, EventArgs e)
		{
			if (ContentChanged != null)
			{
				ContentChanged(sender, e);
			}
		}

		protected virtual void OnInitialized(object sender, EventArgs e)
		{
			if(Initialized != null)
			{
				Initialized(sender, e);
			}
		}

		#endregion

		private void UpdateSelectedContactIndex(int index)
		{
			if (index != -1)
			{
				// Call contact service to do range check on selected index. This will
				// throw if out of range.
				_contactService.GetContact(index);
			}
			_selectedContactIndex = index;
		}
	}
}